package cron.admin;


import cn.hutool.core.net.multipart.UploadFile;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.http.HttpUtil;
import cn.hutool.http.server.HttpServerRequest;
import cn.hutool.http.server.HttpServerResponse;
import cron.admin.service.TaskService;
import jdk.nashorn.internal.ir.debug.JSONWriter;
import jdk.nashorn.internal.parser.JSONParser;

import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpCookie;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Collection;

/**
 * @author : willian fu
 * @version : 1.0
 * @date : 2021/3/3 0003 12:52
 */
public class AdminHttpServer {

    public static AdminHttpServer INSTANCE = new AdminHttpServer();

    private String username = "admin";

    private String psw = "admin";

    private String token;

    private static final String SALT = "^/*~&-%.$.,@";

    private int port = 1000;

    public void stater() {
        try {
            token = this.getMd5Str(username + psw + SALT);
            HttpUtil.createServer(port)
                    .addAction("/", (req, rsp) -> {
                        String path = req.getPath().substring(1);
                        if (StrUtil.isBlank(path)){
                            path = path + "/index.html";
                        }
                        InputStream stream = this.getClass().getClassLoader().getResourceAsStream("admin/" + path);
                        if (null == stream) {
                            rsp.setCharset(StandardCharsets.UTF_8);
                            rsp.write("404 not found");
                        } else {
                            rsp.write(stream);
                            stream.close();
                        }
                    })
                    .addAction("/login", this::doLogin)
                    .addAction("/reset/psw", this::doRePsw)
                    .addAction("/task", this::doTask)
                    .addAction("/task/upload", this::doTask)
                    .start();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    public AdminHttpServer setPort(int port){
        this.port = port;
        return this;
    }

    public AdminHttpServer setAccount(String userName, String password){
        this.username = userName;
        this.psw = password;
        return this;
    }

    private void doTask(HttpServerRequest req, HttpServerResponse rsp){
        if (verifyLogin(req, rsp)) {
            switch (req.getMethod()) {
                case "GET":
                    TaskService.INSTANCE.getTasks(req, rsp);
                    break;
                case "POST":
                    TaskService.INSTANCE.addTasks(req, rsp);
                    break;
                case "PUT":
                    TaskService.INSTANCE.updateTasks(req, rsp);
                    break;
                case "DELETE":
                    TaskService.INSTANCE.delTasks(req, rsp);
                    break;
                default:
                    break;
            }
        }
    }

    private void doLogin(HttpServerRequest req, HttpServerResponse rsp){
        String account = req.getParam("account");
        String psw = req.getParam("psw");
        try {
            if (token.equals(getMd5Str(account + psw + SALT))){
                setCookieLogin(req, rsp);
                rsp.send(200);
                rsp.write("login success");
                return;
            }
        } catch (Exception e) {}
        rsp.send(400);
        rsp.write("login fail !");
    }

    private void doRePsw(HttpServerRequest req, HttpServerResponse rsp){
        if (verifyLogin(req, rsp)){
            rsp.write("doRePsw");
        }
    }

    private boolean verifyLogin(HttpServerRequest req, HttpServerResponse rsp){
        boolean verify = verify(req);
        if (!verify){
            rsp.setHeader("Location","http://" +req.getHeader("Host"));
            rsp.send(302);
        }
        return verify;
    }

    private boolean verify(HttpServerRequest req){
        try {
            String cookies = req.getHeader("Cookie");
            String cookie = "";
            if (StrUtil.isBlank(this.token)){
                this.token = this.getMd5Str(username + psw + SALT);
            }
            for (String ck : cookies.split(";")) {
                String[] split = ck.split("=");
                if ("token".equalsIgnoreCase(split[0].trim())){
                    cookie = split[1];
                    break;
                }
            }
            return this.token.equals(cookie);
        } catch (Exception e) {}
        return false;
    }

    private void setCookieLogin(HttpServerRequest req, HttpServerResponse rsp){
        rsp.addHeader("Set-Cookie", "token=" + token + "; path=/; domain=" + req.getHeader("Host").split(":")[0]);
    }

    private String getMd5Str(String str) throws NoSuchAlgorithmException {
        MessageDigest m = MessageDigest.getInstance("MD5");
        m.update(str.getBytes(StandardCharsets.UTF_8));
        byte[] s = m.digest();
        StringBuilder result = new StringBuilder();
        for (byte b : s) {
            result.append(Integer.toHexString((0x000000FF & b) | 0xFFFFFF00).substring(6));
        }
        return result.toString();
    }
}
